/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
    expect
} from 'chai';
import 'mocha';
import {
    Returnundefined,
    Sttoglobalrecord,
    Tryldglobalbyname,
    Lda,
    VReg,
    Imm,
    IRNode,
    Sta,
    Mov,
    Stobjbyname,
    Dec,
    Definefunc,
    Label,
    Stglobalvar,
    Newobjrange,
    Createobjectwithbuffer,
    Ldglobalvar,
    Eq,
    Jeqz,
    Ldai,
    Jmp,
    Trystglobalbyname,
    LdaStr,
    Defineclasswithbuffer,
    Stlexvar,
    Createemptyarray,
    Callarg1,
    Stownbyindex,
    Callargs2
} from "../src/irnodes";
import { checkInstructions, SnippetCompiler } from "./utils/base";
import { creatAstFromSnippet } from "./utils/asthelper"
import { PandaGen } from '../src/pandagen';

describe("AutoGeneratedIdNameTest", function () {
    it("noNameForAutoGeneratedId", function () {
        let snippetCompiler = new SnippetCompiler();
        snippetCompiler.compileAfter(
            `
                let kk = new Date();
                let list;
                let hh = {name:2};

                function fu(a) {
                    return a;
                }
                let uu = fu(((list = kk) == null ? void 0 : hh) ?? []);
            `, 'test.js');
        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
        let insns = snippetCompiler.getGlobalInsns();
        let expected = [
            new Definefunc(new Imm(0), 'UnitTest.fu', new Imm(1)),
            new Stglobalvar(new Imm(0), 'fu'),
            new Tryldglobalbyname(new Imm(0), 'Date'),
            new Sta(new VReg()),
            new Newobjrange(new Imm(0), new Imm(1), [new VReg()]),
            new Sttoglobalrecord(new Imm(0), 'kk'),
            new Lda(new VReg()),
            new Sttoglobalrecord(new Imm(0), 'list'),
            new Createobjectwithbuffer(new Imm(0), 'test_0'),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Sttoglobalrecord(new Imm(0), 'hh'),
            new Ldglobalvar(new Imm(0), 'fu'),
            new Sta(new VReg()),
            new Tryldglobalbyname(new Imm(0), 'kk'),
            new Trystglobalbyname(new Imm(0), 'list'),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Eq(new Imm(0), new VReg()),
            new Jeqz(new Label()),
            new Ldai(new Imm(0)),
            new Lda(new VReg()),
            new Jmp(new Label()),
            new Label(),
            new Tryldglobalbyname(new Imm(0), 'hh'),
            new Label(),
            new Stglobalvar(new Imm(0), '#a')
        ];
        expect(checkInstructions(insns.slice(0, 27), expected)).to.be.true;
    });

    it("sameNameForDifferentNodeWithSameOrigin", function () {
        let snippetCompiler = new SnippetCompiler();
        snippetCompiler.compileAfter(
            `
                enum hiddenItemAction {
                    str = "string"
                }
                let a = hiddenItemAction.str;
            `, 'test.js');
        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
        let insns = snippetCompiler.getPandaGenByName("UnitTest.#1#").getInsns();
        let expected = [
            new Lda(new VReg()),
            new Sta(new VReg()),
            new Mov(new VReg(), new VReg()),
            new LdaStr('string'),
            new Stobjbyname(new Imm(0), 'str', new VReg()),
            new Returnundefined()
        ];
        expect(checkInstructions(insns, expected)).to.be.true;
    });

    it("allocUniqueNameForAutoGenratedIdWithName", function () {
        let snippetCompiler = new SnippetCompiler();
        snippetCompiler.compileAfter(
            `
                function ccclass(name: string) {
                    return function ccclass(target :any) {
                        target.prototype.name = name;
                    }
                }

                @ccclass('cc.ClickEvent')
                class EventHandler {
                    public static emitEvent(event: EventHandler): boolean {
                        if (!(event instanceof EventHandler)) {
                            return false;
                        }
                        return true;
                    }
                }
            `, 'test.ts');
        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
        let insns = snippetCompiler.getGlobalInsns();
        let expected = [
            new Definefunc(new Imm(0), 'UnitTest.#2#ccclass', new Imm(1)),
            new Stglobalvar(new Imm(0), 'ccclass'),
            new Mov(new VReg(), new VReg()),
            new Defineclasswithbuffer(new Imm(0), 'UnitTest.#3#EventHandler', 'test_1', new Imm(0), new VReg()),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Stlexvar(new Imm(0), new Imm(0)),
            new Lda(new VReg()),
            new Stglobalvar(new Imm(0), 'EventHandler#a'),
            new Sttoglobalrecord(new Imm(0), 'EventHandler'),
            new Tryldglobalbyname(new Imm(0), '__decorate'),
            new Sta(new VReg()),
            new Createemptyarray(new Imm(0)),
            new Sta(new VReg()),
            new Ldglobalvar(new Imm(0), 'ccclass'),
            new Sta(new VReg()),
            new LdaStr('cc.ClickEvent'),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Callarg1(new Imm(0), new VReg()),
            new Stownbyindex(new Imm(0), new VReg(), new Imm(0)),
            new Lda(new VReg()),
            new Sta(new VReg()),
            new Tryldglobalbyname(new Imm(0), 'EventHandler'),
            new Sta(new VReg()),
            new Lda(new VReg()),
            new Callargs2(new Imm(0), new VReg(), new VReg()),
            new Stglobalvar(new Imm(0), 'EventHandler#a'),
            new Trystglobalbyname(new Imm(0), 'EventHandler'),
            new Returnundefined()
        ];
        expect(checkInstructions(insns, expected)).to.be.true;
    });
});
